﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PKHeX.Core
{
    /// <summary>
    /// Logic for converting a <see cref="string"/> for Generation 4.
    /// </summary>
    public static class StringConverter4
    {
        /// <summary>Converts Generation 4 encoded data to decoded string.</summary>
        /// <param name="data">Encoded data</param>
        /// <param name="offset">Offset to read from</param>
        /// <param name="count">Length of data to read.</param>
        /// <returns>Decoded string.</returns>
        public static string GetString4(byte[] data, int offset, int count)
        {
            var s = new StringBuilder();
            for (int i = 0; i < count; i += 2)
            {
                var val = BitConverter.ToUInt16(data, offset + i);
                if (val == 0xFFFF)
                    break;
                var chr = ConvertValue2CharG4(val);
                if (chr == 0xFFFF)
                    break;
                s.Append((char)chr);
            }
            return StringConverter.SanitizeString(s.ToString());
        }

        /// <summary>Gets the bytes for a 4th Generation String</summary>
        /// <param name="value">Decoded string.</param>
        /// <param name="maxLength">Maximum length</param>
        /// <param name="padTo">Pad to given length</param>
        /// <param name="padWith">Pad with value</param>
        /// <returns>Encoded data.</returns>
        public static byte[] SetString4(string value, int maxLength, int padTo = 0, ushort padWith = 0)
        {
            if (value.Length > maxLength)
                value = value.Substring(0, maxLength); // Hard cap
            var temp = StringConverter.UnSanitizeString(value, 4) // Replace Special Characters and add Terminator
                .PadRight(value.Length + 1, (char)0xFFFF) // Null Terminator
                .PadRight(padTo, (char)padWith); // Padding

            var data = new byte[temp.Length * 2];
            for (int i = 0; i < temp.Length; i++)
            {
                var chr = temp[i];
                var val = ConvertChar2ValueG4(chr);
                BitConverter.GetBytes(val).CopyTo(data, i * 2);
            }
            return data;
        }

        /// <summary>
        /// Converts Generation 4 Big Endian encoded character data to string.
        /// </summary>
        /// <param name="data">Byte array containing encoded character data.</param>
        /// <param name="offset">Offset to read from</param>
        /// <param name="count">Length of data to read.</param>
        /// <returns>Converted string.</returns>
        public static string GetBEString4(byte[] data, int offset, int count)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < count; i += 2)
            {
                var val = BigEndian.ToUInt16(data, offset + i);
                if (val == 0xFFFF)
                    break;
                var chr = ConvertValue2CharG4(val);
                if (chr == 0xFFFF)
                    break;
                sb.Append((char)chr);
            }
            return StringConverter.SanitizeString(sb.ToString());
        }

        /// <summary>
        /// Converts a string to Generation 4 Big Endian encoded character data.
        /// </summary>
        /// <param name="value">String to be converted.</param>
        /// <param name="maxLength">Maximum length of string</param>
        /// <param name="padTo">Pad to given length</param>
        /// <param name="padWith">Pad with value</param>
        /// <returns>Byte array containing encoded character data</returns>
        public static byte[] SetBEString4(string value, int maxLength, int padTo = 0, ushort padWith = 0)
        {
            if (value.Length > maxLength)
                value = value.Substring(0, maxLength); // Hard cap

            var temp = StringConverter.UnSanitizeString(value, 4) // Replace Special Characters and add Terminator
                .PadRight(value.Length + 1, (char)0xFFFF) // Null Terminator
                .PadRight(padTo, (char)padWith); // Padding

            var data = new byte[temp.Length * 2];
            for (int i = 0; i < temp.Length; i++)
            {
                var chr = temp[i];
                var val = ConvertChar2ValueG4(chr);
                BigEndian.GetBytes(val).CopyTo(data, i * 2);
            }
            return data;
        }

        /// <summary>
        /// Converts a Generation 4 value to Unicode character.
        /// </summary>
        /// <param name="val">Encoded value.</param>
        /// <returns>Decoded value (unicode).</returns>
        private static ushort ConvertValue2CharG4(ushort val)
        {
            return G4ValueId.TryGetValue(val, out int index)
                ? G4Chars[index] : ushort.MaxValue;
        }

        /// <summary>
        /// Converts a Unicode character to Generation 4 value.
        /// </summary>
        /// <param name="chr">Decoded value (unicode).</param>
        /// <returns>Encoded value.</returns>
        private static ushort ConvertChar2ValueG4(ushort chr)
        {
            if (chr == '\'') // apostrophe, used by Farfetch'd
                return 0x1B3; // here rather than in static constructor to prevent byte[]->str outputting ’ instead of '
            return G4CharId.TryGetValue(chr, out int index)
                ? G4Values[index] : ushort.MaxValue;
        }

        /// <summary>
        /// Strips diacritics on gen1-4 french pkm names
        /// </summary>
        /// <param name="input">String to clean</param>
        /// <returns>Cleaned string</returns>
        /// <remarks>Only 4 characters are accented in gen1-4</remarks>
        public static string StripDiacriticsFR4(string input)
        {
            var result = new StringBuilder(input.Length);
            foreach (var c in input)
                result.Append(FrDiacritic.TryGetValue(c, out char o) ? o : c);
            return result.ToString();
        }

        private static readonly Dictionary<char, char> FrDiacritic = new Dictionary<char, char>(4)
        {
            { 'È', 'E' },
            { 'É', 'E' },
            { 'Ê', 'E' },
            { 'Ï', 'I' },
        };

        #region Conversion Data

        /// <summary>
        /// Values (stored value)
        /// </summary>
        private static readonly ushort[] G4Values =
        {
            00001, 00002, 00003, 00004, 00005, 00006, 00007, 00008, 00009, 00010, 00011, 00012, 00013, 00014, 00015, 00016,
            00017, 00018, 00019, 00020, 00021, 00022, 00023, 00024, 00025, 00026, 00027, 00028, 00029, 00030, 00031, 00032,
            00033, 00034, 00035, 00036, 00037, 00038, 00039, 00040, 00041, 00042, 00043, 00044, 00045, 00046, 00047, 00048,
            00049, 00050, 00051, 00052, 00053, 00054, 00055, 00056, 00057, 00058, 00059, 00060, 00061, 00062, 00063, 00064,
            00065, 00066, 00067, 00068, 00069, 00070, 00071, 00072, 00073, 00074, 00075, 00076, 00077, 00078, 00079, 00080,
            00081, 00082, 00083, 00084, 00085, 00086, 00087, 00088, 00089, 00090, 00091, 00092, 00093, 00094, 00095, 00096,
            00097, 00098, 00099, 00100, 00101, 00102, 00103, 00104, 00105, 00106, 00107, 00108, 00109, 00110, 00111, 00112,
            00113, 00114, 00115, 00116, 00117, 00118, 00119, 00120, 00121, 00122, 00123, 00124, 00125, 00126, 00127, 00128,
            00129, 00130, 00131, 00132, 00133, 00134, 00135, 00136, 00137, 00138, 00139, 00140, 00141, 00142, 00143, 00144,
            00145, 00146, 00147, 00148, 00149, 00150, 00151, 00152, 00153, 00154, 00155, 00156, 00157, 00158, 00159, 00160,
            00161, 00162, 00163, 00164, 00165, 00166, 00167, 00168, 00169, 00170, 00171, 00172, 00173, 00174, 00175, 00176,
            00177, 00178, 00179, 00180, 00181, 00182, 00183, 00184, 00185, 00186, 00187, 00188, 00189, 00190, 00191, 00192,
            00193, 00194, 00195, 00196, 00197, 00198, 00199, 00200, 00201, 00202, 00203, 00204, 00205, 00206, 00207, 00208,
            00209, 00210, 00211, 00212, 00213, 00214, 00215, 00216, 00217, 00218, 00219, 00220, 00221, 00222, 00223, 00225,
            00226, 00227, 00228, 00229, 00230, 00231, 00232, 00233, 00234, 00235, 00236, 00237, 00238, 00239, 00240, 00241,
            00242, 00243, 00244, 00245, 00246, 00247, 00248, 00249, 00250, 00251, 00252, 00253, 00254, 00255, 00256, 00257,
            00258, 00259, 00260, 00261, 00262, 00263, 00264, 00265, 00266, 00267, 00268, 00269, 00270, 00271, 00272, 00273,
            00274, 00275, 00276, 00277, 00278, 00279, 00280, 00281, 00282, 00283, 00284, 00285, 00286, 00287, 00288, 00289,
            00290, 00291, 00292, 00293, 00294, 00295, 00296, 00297, 00298, 00299, 00300, 00301, 00302, 00303, 00304, 00305,
            00306, 00307, 00308, 00309, 00310, 00311, 00312, 00313, 00314, 00315, 00316, 00317, 00318, 00319, 00320, 00321,
            00322, 00323, 00324, 00325, 00326, 00327, 00328, 00329, 00330, 00331, 00332, 00333, 00334, 00335, 00336, 00337,
            00338, 00339, 00340, 00341, 00342, 00343, 00344, 00345, 00346, 00347, 00348, 00349, 00350, 00351, 00352, 00353,
            00354, 00355, 00356, 00357, 00358, 00359, 00360, 00361, 00362, 00363, 00364, 00365, 00366, 00367, 00368, 00369,
            00370, 00371, 00372, 00373, 00374, 00375, 00376, 00377, 00378, 00379, 00380, 00381, 00382, 00383, 00384, 00385,
            00386, 00387, 00388, 00389, 00390, 00391, 00392, 00393, 00394, 00395, 00396, 00397, 00398, 00399, 00400, 00401,
            00402, 00403, 00404, 00405, 00406, 00407, 00408, 00409, 00410, 00411, 00412, 00413, 00414, 00415, 00416, 00417,
            00418, 00419, 00420, 00421, 00422, 00423, 00424, 00425, 00426, 00427, 00428, 00429, 00430, 00431, 00432, 00433,
            00434, 00435, 00436, 00437, 00438, 00439, 00440, 00441, 00442, 00443, 00444, 00445, 00446, 00447, 00448, 00449,
            00450, 00451, 00452, 00453, 00454, 00455, 00456, 00457, 00458, 00459, 00460, 00461, 00462, 00463, 00464, 00465,
            00466, 00467, 00468, 00469, 00470, 00471, 00472, 00473, 00474, 00475, 00476, 00477, 00478, 00479, 00480, 00481,
            00488, 00489, 00490, 01025, 01026, 01027, 01028, 01029, 01030, 01031, 01032, 01033, 01034, 01035, 01036, 01037,
            01038, 01039, 01040, 01041, 01042, 01043, 01044, 01045, 01046, 01047, 01048, 01049, 01050, 01051, 01052, 01053,
            01054, 01055, 01056, 01057, 01058, 01059, 01060, 01061, 01062, 01063, 01064, 01065, 01066, 01067, 01068, 01069,
            01070, 01071, 01072, 01073, 01074, 01075, 01076, 01077, 01078, 01079, 01080, 01081, 01082, 01083, 01084, 01085,
            01086, 01087, 01088, 01089, 01090, 01091, 01092, 01093, 01094, 01095, 01096, 01097, 01098, 01099, 01100, 01101,
            01102, 01103, 01104, 01105, 01106, 01107, 01108, 01109, 01110, 01111, 01112, 01113, 01114, 01115, 01116, 01117,
            01118, 01119, 01120, 01121, 01122, 01123, 01124, 01125, 01126, 01127, 01128, 01129, 01130, 01131, 01132, 01133,
            01134, 01135, 01136, 01137, 01138, 01139, 01140, 01141, 01142, 01143, 01144, 01145, 01146, 01147, 01148, 01149,
            01150, 01151, 01152, 01153, 01154, 01155, 01156, 01157, 01158, 01159, 01160, 01161, 01162, 01163, 01164, 01165,
            01166, 01167, 01168, 01169, 01170, 01171, 01172, 01173, 01174, 01175, 01176, 01177, 01178, 01179, 01180, 01181,
            01182, 01183, 01184, 01185, 01186, 01187, 01188, 01189, 01190, 01191, 01192, 01193, 01194, 01195, 01196, 01197,
            01198, 01199, 01200, 01201, 01202, 01203, 01204, 01205, 01206, 01207, 01208, 01209, 01210, 01211, 01212, 01213,
            01214, 01215, 01216, 01217, 01218, 01219, 01220, 01221, 01222, 01223, 01224, 01225, 01226, 01227, 01228, 01229,
            01230, 01231, 01232, 01233, 01234, 01235, 01236, 01237, 01238, 01239, 01240, 01241, 01242, 01243, 01244, 01245,
            01246, 01247, 01248, 01249, 01250, 01251, 01252, 01253, 01254, 01255, 01256, 01257, 01258, 01259, 01260, 01261,
            01262, 01263, 01264, 01265, 01266, 01267, 01268, 01269, 01270, 01271, 01272, 01273, 01274, 01275, 01276, 01277,
            01278, 01279, 01280, 01281, 01282, 01283, 01284, 01285, 01286, 01287, 01288, 01289, 01290, 01291, 01292, 01293,
            01294, 01295, 01296, 01297, 01298, 01299, 01300, 01301, 01302, 01303, 01304, 01305, 01306, 01307, 01308, 01309,
            01310, 01311, 01312, 01313, 01314, 01315, 01316, 01317, 01318, 01319, 01320, 01321, 01322, 01323, 01324, 01325,
            01326, 01327, 01328, 01329, 01330, 01331, 01332, 01333, 01334, 01335, 01336, 01337, 01338, 01339, 01340, 01341,
            01342, 01343, 01344, 01345, 01346, 01347, 01348, 01349, 01350, 01351, 01352, 01353, 01354, 01355, 01356, 01357,
            01358, 01359, 01360, 01361, 01362, 01363, 01364, 01365, 01366, 01367, 01368, 01369, 01370, 01371, 01372, 01373,
            01374, 01375, 01376, 01377, 01378, 01379, 01380, 01381, 01382, 01383, 01384, 01385, 01386, 01387, 01388, 01389,
            01390, 01391, 01392, 01393, 01394, 01395, 01396, 01397, 01398, 01399, 01400, 01401, 01402, 01403, 01404, 01405,
            01406, 01407, 01408, 01409, 01410, 01411, 01412, 01413, 01414, 01415, 01416, 01417, 01418, 01419, 01420, 01421,
            01422, 01423, 01424, 01425, 01426, 01427, 01428, 01429, 01430, 01431, 01432, 01433, 01434, 01435, 01436, 01437,
            01438, 01439, 01440, 01441, 01442, 01443, 01444, 01445, 01446, 01447, 01448, 01449, 01450, 01451, 01452, 01453,
            01454, 01455, 01456, 01457, 01458, 01459, 01460, 01461, 01462, 01463, 01464, 01465, 01466, 01467, 01468, 01469,
            01470, 01471, 01472, 01473, 01474, 01475, 01476, 01477, 01478, 01479, 01480, 01481, 01482, 01483, 01484, 01485,
            01486, 01487, 01488, 01489, 01490, 01491, 01492, 01493, 01494, 01495, 01496, 01497, 01498, 01499, 01500, 01501,
            01502, 01503, 01504, 01505, 01506, 01507, 01508, 01509, 01510, 01511, 01512, 01513, 01514, 01515, 01516, 01517,
            01518, 01519, 01520, 01521, 01522, 01523, 01524, 01525, 01526, 01527, 01528, 01529, 01530, 01531, 01532, 01533,
            01534, 01535, 01536, 01537, 01538, 01539, 01540, 01541, 01542, 01543, 01544, 01545, 01546, 01547, 01548, 01549,
            01550, 01551, 01552, 01553, 01554, 01555, 01556, 01557, 01558, 01559, 01560, 01561, 01562, 01563, 01564, 01565,
            01566, 01567, 01568, 01569, 01570, 01571, 01572, 01573, 01574, 01575, 01576, 01577, 01578, 01579, 01580, 01581,
            01582, 01583, 01584, 01585, 01586, 01587, 01588, 01589, 01590, 01591, 01592, 01593, 01594, 01595, 01596, 01597,
            01598, 01599, 01600, 01601, 01602, 01603, 01604, 01605, 01606, 01607, 01608, 01609, 01610, 01611, 01612, 01613,
            01614, 01615, 01616, 01617, 01618, 01619, 01620, 01621, 01622, 01623, 01624, 01625, 01626, 01627, 01628, 01629,
            01630, 01631, 01632, 01633, 01634, 01635, 01636, 01637, 01638, 01639, 01640, 01641, 01642, 01643, 01644, 01645,
            01646, 01647, 01648, 01649, 01650, 01651, 01652, 01653, 01654, 01655, 01656, 01657, 01658, 01659, 01660, 01661,
            01662, 01663, 01664, 01665, 01666, 01667, 01668, 01669, 01670, 01671, 01672, 01673, 01674, 01675, 01676, 01677,
            01678, 01679, 01680, 01681, 01682, 01683, 01684, 01685, 01686, 01687, 01688, 01689, 01690, 01691, 01692, 01693,
            01694, 01695, 01696, 01697, 01698, 01699, 01700, 01701, 01702, 01703, 01704, 01705, 01706, 01707, 01708, 01709,
            01710, 01711, 01712, 01713, 01714, 01715, 01716, 01717, 01718, 01719, 01720, 01721, 01722, 01723, 01724, 01725,
            01726, 01727, 01728, 01729, 01730, 01731, 01732, 01733, 01734, 01735, 01736, 01737, 01738, 01739, 01740, 01741,
            01742, 01743, 01744, 01745, 01746, 01747, 01748, 01749, 01750, 01751, 01752, 01753, 01754, 01755, 01756, 01757,
            01758, 01759, 01760, 01761, 01762, 01763, 01764, 01765, 01766, 01767, 01768, 01769, 01770, 01771, 01772, 01773,
            01774, 01775, 01776, 01777, 01778, 01779, 01780, 01781, 01782, 01783, 01784, 01785, 01786, 01787, 01788, 01789,
            01790, 01791, 01792, 01793, 01794, 01795, 01796, 01797, 01798, 01799, 01800, 01801, 01802, 01803, 01804, 01805,
            01806, 01807, 01808, 01809, 01810, 01811, 01812, 01813, 01814, 01815, 01816, 01817, 01818, 01819, 01820, 01821,
            01822, 01823, 01824, 01825, 01826, 01827, 01828, 01829, 01830, 01831, 01832, 01833, 01834, 01835, 01836, 01837,
            01838, 01839, 01840, 01841, 01842, 01843, 01844, 01845, 01846, 01847, 01848, 01849, 01850, 01851, 01852, 01853,
            01854, 01855, 01856, 01857, 01858, 01859, 01860, 01861, 01862, 01863, 01864, 01865, 01866, 01867, 01868, 01869,
            01870, 01871, 01872, 01873, 01874, 01875, 01876, 01877, 01878, 01879, 01880, 01881, 01882, 01883, 01884, 01885,
            01886, 01887, 01888, 01889, 01890, 01891, 01892, 01893, 01894, 01895, 01896, 01897, 01898, 01899, 01900, 01901,
            01902, 01903, 01904, 01905, 01906, 01907, 01908, 01909, 01910, 01911, 01912, 01913, 01914, 01915, 01916, 01917,
            01918, 01919, 01920, 01921, 01922, 01923, 01924, 01925, 01926, 01927, 01928, 01929, 01930, 01931, 01932, 01933,
            01934, 01935, 01936, 01937, 01938, 01939, 01940, 01941, 01942, 01943, 01944, 01945, 01946, 01947, 01948, 01949,
            01950, 01951, 01952, 01953, 01954, 01955, 01956, 01957, 01958, 01959, 01960, 01961, 01962, 01963, 01964, 01965,
            01966, 01967, 01968, 01969, 01970, 01971, 01972, 01973, 01974, 01975, 01976, 01977, 01978, 01979, 01980, 01981,
            01982, 01983, 01984, 01985, 01986, 01987, 01988, 01989, 01990, 01991, 01992, 01993, 01994, 01995, 01996, 01997,
            01998, 01999, 02000, 02001, 02002, 02003, 02004, 02005, 02006, 02007, 02008, 02009, 02010, 02011, 02012, 02013,
            02014, 02015, 02016, 02017, 02018, 02019, 02020, 02021, 02022, 02023, 02024, 02025, 02026, 02027, 02028, 02029,
            02030, 02031, 02032, 02033, 02034, 02035, 02036, 02037, 02038, 02039, 02040, 02041, 02042, 02043, 02044, 02045,
            02046, 02047, 02048, 02049, 02050, 02051, 02052, 02053, 02054, 02055, 02056, 02057, 02058, 02059, 02060, 02061,
            02062, 02063, 02064, 02065, 02066, 02067, 02068, 02069, 02070, 02071, 02072, 02073, 02074, 02075, 02076, 02077,
            02078, 02079, 02080, 02081, 02082, 02083, 02084, 02085, 02086, 02087, 02088, 02089, 02090, 02091, 02092, 02093,
            02094, 02095, 02096, 02097, 02098, 02099, 02100, 02101, 02102, 02103, 02104, 02105, 02106, 02107, 02108, 02109,
            02110, 02111, 02112, 02113, 02114, 02115, 02116, 02117, 02118, 02119, 02120, 02121, 02122, 02123, 02124, 02125,
            02126, 02127, 02128, 02129, 02130, 02131, 02132, 02133, 02134, 02135, 02136, 02137, 02138, 02139, 02140, 02141,
            02142, 02143, 02144, 02145, 02146, 02147, 02148, 02149, 02150, 02151, 02152, 02153, 02154, 02155, 02156, 02157,
            02158, 02159, 02160, 02161, 02162, 02163, 02164, 02165, 02166, 02167, 02168, 02169, 02170, 02171, 02172, 02173,
            02174, 02175, 02176, 02177, 02178, 02179, 02180, 02181, 02182, 02183, 02184, 02185, 02186, 02187, 02188, 02189,
            02190, 02191, 02192, 02193, 02194, 02195, 02196, 02197, 02198, 02199, 02200, 02201, 02202, 02203, 02204, 02205,
            02206, 02207, 02208, 02209, 02210, 02211, 02212, 02213, 02214, 02215, 02216, 02217, 02218, 02219, 02220, 02221,
            02222, 02223, 02224, 02225, 02226, 02227, 02228, 02229, 02230, 02231, 02232, 02233, 02234, 02235, 02236, 02237,
            02238, 02239, 02240, 02241, 02242, 02243, 02244, 02245, 02246, 02247, 02248, 02249, 02250, 02251, 02252, 02253,
            02254, 02255, 02256, 02257, 02258, 02259, 02260, 02261, 02262, 02263, 02264, 02265, 02266, 02267, 02268, 02269,
            02270, 02271, 02272, 02273, 02274, 02275, 02276, 02277, 02278, 02279, 02280, 02281, 02282, 02283, 02284, 02285,
            02286, 02287, 02288, 02289, 02290, 02291, 02292, 02293, 02294, 02295, 02296, 02297, 02298, 02299, 02300, 02301,
            02302, 02303, 02304, 02305, 02306, 02307, 02308, 02309, 02310, 02311, 02312, 02313, 02314, 02315, 02316, 02317,
            02318, 02319, 02320, 02321, 02322, 02323, 02324, 02325, 02326, 02327, 02328, 02329, 02330, 02331, 02332, 02333,
            02334, 02335, 02336, 02337, 02338, 02339, 02340, 02341, 02342, 02343, 02344, 02345, 02346, 02347, 02348, 02349,
            02350, 02351, 02352, 02353, 02354, 02355, 02356, 02357, 02358, 02359, 02360, 02361, 02362, 02363, 02364, 02365,
            02366, 02367, 02368, 02369, 02370, 02371, 02372, 02373, 02374, 02375, 02376, 02377, 02378, 02379, 02380, 02381,
            02382, 02383, 02384, 02385, 02386, 02387, 02388, 02389, 02390, 02391, 02392, 02393, 02394, 02395, 02396, 02397,
            02398, 02399, 02400, 02401, 02402, 02403, 02404, 02405, 02406, 02407, 02408, 02409, 02410, 02411, 02412, 02413,
            02414, 02415, 02416, 02417, 02418, 02419, 02420, 02421, 02422, 02423, 02424, 02425, 02426, 02427, 02428, 02429,
            02430, 02431, 02432, 02433, 02434, 02435, 02436, 02437, 02438, 02439, 02440, 02441, 02442, 02443, 02444, 02445,
            02446, 02447, 02448, 02449, 02450, 02451, 02452, 02453, 02454, 02455, 02456, 02457, 02458, 02459, 02460, 02461,
            02462, 02463, 02464, 02465, 02466, 02467, 02468, 02469, 02470, 02471, 02472, 02473, 02474, 02475, 02476, 02477,
            02478, 02479, 02480, 02481, 02482, 02483, 02484, 02485, 02486, 02487, 02488, 02489, 02490, 02491, 02492, 02493,
            02494, 02495, 02496, 02497, 02498, 02499, 02500, 02501, 02502, 02503, 02504, 02505, 02506, 02507, 02508, 02509,
            02510, 02511, 02512, 02513, 02514, 02515, 02516, 02517, 02518, 02519, 02520, 02521, 02522, 02523, 02524, 02525,
            02526, 02527, 02528, 02529, 02530, 02531, 02532, 02533, 02534, 02535, 02536, 02537, 02538, 02539, 02540, 02541,
            02542, 02543, 02544, 02545, 02546, 02547, 02548, 02549, 02550, 02551, 02552, 02553, 02554, 02555, 02556, 02557,
            02558, 02559, 02560, 02561, 02562, 02563, 02564, 02565, 02566, 02567, 02568, 02569, 02570, 02571, 02572, 02573,
            02574, 02575, 02576, 02577, 02578, 02579, 02580, 02581, 02582, 02583, 02584, 02585, 02586, 02587, 02588, 02589,
            02590, 02591, 02592, 02593, 02594, 02595, 02596, 02597, 02598, 02599, 02600, 02601, 02602, 02603, 02604, 02605,
            02606, 02607, 02608, 02609, 02610, 02611, 02612, 02613, 02614, 02615, 02616, 02617, 02618, 02619, 02620, 02621,
            02622, 02623, 02624, 02625, 02626, 02627, 02628, 02629, 02630, 02631, 02632, 02633, 02634, 02635, 02636, 02637,
            02638, 02639, 02640, 02641, 02642, 02643, 02644, 02645, 02646, 02647, 02648, 02649, 02650, 02651, 02652, 02653,
            02654, 02655, 02656, 02657, 02658, 02659, 02660, 02661, 02662, 02663, 02664, 02665, 02666, 02667, 02668, 02669,
            02670, 02671, 02672, 02673, 02674, 02675, 02676, 02677, 02678, 02679, 02680, 02681, 02682, 02683, 02684, 02685,
            02686, 02687, 02688, 02689, 02690, 02691, 02692, 02693, 02694, 02695, 02696, 02697, 02698, 02699, 02700, 02701,
            02702, 02703, 02704, 02705, 02706, 02707, 02708, 02709, 02710, 02711, 02712, 02713, 02714, 02715, 02716, 02717,
            02718, 02719, 02720, 02721, 02722, 02723, 02724, 02725, 02726, 02727, 02728, 02729, 02730, 02731, 02732, 02733,
            02734, 02735, 02736, 02737, 02738, 02739, 02740, 02741, 02742, 02743, 02744, 02745, 02746, 02747, 02748, 02749,
            02750, 02751, 02752, 02753, 02754, 02755, 02756, 02757, 02758, 02759, 02760, 02761, 02762, 02763, 02764, 02765,
            02766, 02767, 02768, 02769, 02770, 02771, 02772, 02773, 02774, 02775, 02776, 02777, 02778, 02779, 02780, 02781,
            02782, 02783, 02784, 02785, 02786, 02787, 02788, 02789, 02790, 02791, 02792, 02793, 02794, 02795, 02796, 02797,
            02798, 02799, 02800, 02801, 02802, 02803, 02804, 02805, 02806, 02807, 02808, 02809, 02810, 02811, 02812, 02813,
            02814, 02815, 02816, 02817, 02818, 02819, 02820, 02821, 02822, 02823, 02824, 02825, 02826, 02827, 02828, 02829,
            02830, 02831, 02832, 02833, 02834, 02835, 02836, 02837, 02838, 02839, 02840, 02841, 02842, 02843, 02844, 02845,
            02846, 02847, 02848, 02849, 02850, 02851, 02852, 02853, 02854, 02855, 02856, 02857, 02858, 02859, 02860, 02861,
            02862, 02863, 02864, 02865, 02866, 02867, 02868, 02869, 02870, 02871, 02872, 02873, 02874, 02875, 02876, 02877,
            02878, 02879, 02880, 02881, 02882, 02883, 02884, 02885, 02886, 02887, 02888, 02889, 02890, 02891, 02892, 02893,
            02894, 02895, 02896, 02897, 02898, 02899, 02900, 02901, 02902, 02903, 02904, 02905, 02906, 02907, 02908, 02909,
            02910, 02911, 02912, 02913, 02914, 02915, 02916, 02917, 02918, 02919, 02920, 02921, 02922, 02923, 02924, 02925,
            02926, 02927, 02928, 02929, 02930, 02931, 02932, 02933, 02934, 02935, 02936, 02937, 02938, 02939, 02940, 02941,
            02942, 02943, 02944, 02945, 02946, 02947, 02948, 02949, 02950, 02951, 02952, 02953, 02954, 02955, 02956, 02957,
            02958, 02959, 02960, 02961, 02962, 02963, 02964, 02965, 02966, 02967, 02968, 02969, 02970, 02971, 02972, 02973,
            02974, 02975, 02976, 02977, 02978, 02979, 02980, 02981, 02982, 02983, 02984, 02985, 02986, 02987, 02988, 02989,
            02990, 02991, 02992, 02993, 02994, 02995, 02996, 02997, 02998, 02999, 03000, 03001, 03002, 03003, 03004, 03005,
            03006, 03007, 03008, 03009, 03010, 03011, 03012, 03013, 03014, 03015, 03016, 03017, 03018, 03019, 03020, 03021,
            03022, 03023, 03024, 03025, 03026, 03027, 03028, 03029, 03030, 03031, 03032, 03033, 03034, 03035, 03036, 03037,
            03038, 03039, 03040, 03041, 03042, 03043, 03044, 03045, 03046, 03047, 03048, 03049, 03050, 03051, 03052, 03053,
            03054, 03055, 03056, 03057, 03058, 03059, 03060, 03061, 03062, 03063, 03064, 03065, 03066, 03067, 03068, 03069,
            03070, 03071, 03072, 03073, 03074, 03075, 03076, 03077, 03078, 03079, 03080, 03081, 03082, 03083, 03084, 03085,
            03086, 03087, 03088, 03089, 03090, 03091, 03092, 03093, 03094, 03095, 03096, 03097, 03098, 03099, 03100, 03101,
            03102, 03103, 03104, 03105, 03106, 03107, 03108, 03109, 03110, 03111, 03112, 03113, 03114, 03115, 03116, 03117,
            03118, 03119, 03120, 03121, 03122, 03123, 03124, 03125, 03126, 03127, 03128, 03129, 03130, 03131, 03132, 03133,
            03134, 03135, 03136, 03137, 03138, 03139, 03140, 03141, 03142, 03143, 03144, 03145, 03146, 03147, 03148, 03149,
            03150, 03151, 03152, 03153, 03154, 03155, 03156, 03157, 03158, 03159, 03160, 03161, 03162, 03163, 03164, 03165,
            03166, 03167, 03168, 03169, 03170, 03171, 03172, 03173, 03174, 03175, 03176, 03177, 03178, 03179, 03180, 03181,
            03182, 03183, 03184, 03185, 03186, 03187, 03188, 03189, 03190, 03191, 03192, 03193, 03194, 03195, 03196, 03197,
            03198, 03199, 03200, 03201, 03202, 03203, 03204, 03205, 03206, 03207, 03208, 03209, 03210, 03211, 03212, 03213,
            03214, 03215, 03216, 03217, 03218, 03219, 03220, 03221, 03222, 03223, 03224, 03225, 03226, 03227, 03228, 03229,
            03230, 03231, 03232, 03233, 03234, 03235, 03236, 03237, 03238, 03239, 03240, 03241, 03242, 03243, 03244, 03245,
            03246, 03247, 03248, 03249, 03250, 03251, 03252, 03253, 03254, 03255, 03256, 03257, 03258, 03259, 03260, 03261,
            03262, 03263, 03264, 03265, 03266, 03267, 03268, 03269, 03270, 03271, 03272, 03273, 03274, 03275, 03276, 03277,
            03278, 03279, 03280, 03281, 03282, 03283, 03284, 03285, 03286, 03287, 03288, 03289, 03290, 03291, 03292, 03293,
            03294, 03295, 03296, 03297, 03298, 03299, 03300, 03301, 03302, 03303, 03304, 03305, 03306, 03307, 03308, 03309,
            03310, 03311, 03312, 03313, 03314, 03315, 03316, 03317, 03318, 03319, 03320, 03321, 03322, 03323, 03324, 03325,
            03326, 03327, 03328, 03329, 03330, 03331, 03332, 03333, 03334, 03335, 03336, 03337, 03338, 03339, 03340, 03341,
            03342, 03343, 03344, 03345, 03346, 03347, 03348, 03349, 03350, 03351, 03352, 03353, 03354, 03355, 03356, 03357,
            03358, 03359, 03360, 03361, 03362, 03363, 03364, 03365, 03366, 03367, 03368, 03369, 03370, 03371, 03372, 03373,
            03374, 03377, 03378, 03379, 03380, 03381, 03382, 03383, 03384, 03385, 03386, 03387, 03388, 03389, 03390, 03391,
            03392, 03393, 03394, 03395, 03396, 03397, 03398, 03399, 03400, 03401, 03402, 03403, 03404, 03405, 03406, 03407,
            03408, 03409, 03425, 03426, 03427, 03428, 03429, 65535,
        };

        /// <summary>
        /// Characters (Unicode representation)
        /// </summary>
        private static readonly ushort[] G4Chars =
        {
            12288, 12353, 12354, 12355, 12356, 12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367,
            12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383,
            12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, 12398, 12399,
            12400, 12401, 12402, 12403, 12404, 12405, 12406, 12407, 12408, 12409, 12410, 12411, 12412, 12413, 12414, 12415,
            12416, 12417, 12418, 12419, 12420, 12421, 12422, 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12431, 12434,
            12435, 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463,
            12464, 12465, 12466, 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479,
            12480, 12481, 12482, 12483, 12484, 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, 12494, 12495,
            12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, 12507, 12508, 12509, 12510, 12511,
            12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, 12520, 12521, 12522, 12523, 12524, 12525, 12527, 12530,
            12531, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, 65305, 65313, 65314, 65315, 65316, 65317,
            65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, 65333,
            65334, 65335, 65336, 65337, 65338, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355,
            65356, 65357, 65358, 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 65281,
            65311, 12289, 12290, 08943, 12539, 65295, 12300, 12301, 12302, 12303, 65288, 65289, 09325, 09326, 65291, 12540,
            09319, 09320, 65309, 65370, 65306, 65307, 65294, 65292, 09327, 09328, 09329, 09330, 09331, 09332, 09333, 09334,
            09335, 09336, 65312, 09337, 65285, 09338, 09339, 09341, 10052, 09739, 09812, 09813, 09738, 08663, 08664, 09790,
            00165, 09800, 09801, 09802, 09803, 09804, 09805, 09806, 09807, 08592, 08593, 08595, 08594, 08227, 65286, 00048,
            00049, 00050, 00051, 00052, 00053, 00054, 00055, 00056, 00057, 00065, 00066, 00067, 00068, 00069, 00070, 00071,
            00072, 00073, 00074, 00075, 00076, 00077, 00078, 00079, 00080, 00081, 00082, 00083, 00084, 00085, 00086, 00087,
            00088, 00089, 00090, 00097, 00098, 00099, 00100, 00101, 00102, 00103, 00104, 00105, 00106, 00107, 00108, 00109,
            00110, 00111, 00112, 00113, 00114, 00115, 00116, 00117, 00118, 00119, 00120, 00121, 00122, 00192, 00193, 00194,
            00195, 00196, 00197, 00198, 00199, 00200, 00201, 00202, 00203, 00204, 00205, 00206, 00207, 00208, 00209, 00210,
            00211, 00212, 00213, 00214, 00215, 00216, 00217, 00218, 00219, 00220, 00221, 00222, 00223, 00224, 00225, 00226,
            00227, 00228, 00229, 00230, 00231, 00232, 00233, 00234, 00235, 00236, 00237, 00238, 00239, 00240, 00241, 00242,
            00243, 00244, 00245, 00246, 00247, 00248, 00249, 00250, 00251, 00252, 00253, 00254, 00255, 00338, 00339, 00350,
            00351, 00170, 00186, 00185, 00178, 00179, 00036, 00161, 00191, 00033, 00063, 00044, 00046, 09324, 65381, 00047,
            08216, 08217, 08220, 08221, 08222, 12298, 12299, 00040, 00041, 09794, 09792, 00043, 00045, 00042, 00035, 00061,
            00038, 00126, 00058, 00059, 09327, 09328, 09329, 09330, 09331, 09332, 09333, 09334, 09335, 09336, 00064, 09337,
            00037, 09338, 09339, 09340, 09341, 09342, 09343, 09344, 09345, 09346, 09347, 09348, 00032, 09349, 09350, 09351,
            00176, 00095, 65343, 44032, 44033, 44036, 44039, 44040, 44041, 44042, 44048, 44049, 44050, 44051, 44052, 44053,
            44054, 44055, 44057, 44058, 44059, 44060, 44061, 44064, 44068, 44076, 44077, 44079, 44080, 44081, 44088, 44089,
            44092, 44096, 44107, 44109, 44116, 44120, 44124, 44144, 44145, 44148, 44151, 44152, 44154, 44160, 44161, 44163,
            44164, 44165, 44166, 44169, 44170, 44171, 44172, 44176, 44180, 44188, 44189, 44191, 44192, 44193, 44200, 44201,
            44202, 44204, 44207, 44208, 44216, 44217, 44219, 44220, 44221, 44225, 44228, 44232, 44236, 44245, 44247, 44256,
            44257, 44260, 44263, 44264, 44266, 44268, 44271, 44272, 44273, 44275, 44277, 44278, 44284, 44285, 44288, 44292,
            44294, 44300, 44301, 44303, 44305, 44312, 44316, 44320, 44329, 44332, 44333, 44340, 44341, 44344, 44348, 44356,
            44357, 44359, 44361, 44368, 44372, 44376, 44385, 44387, 44396, 44397, 44400, 44403, 44404, 44405, 44406, 44411,
            44412, 44413, 44415, 44417, 44418, 44424, 44425, 44428, 44432, 44444, 44445, 44452, 44471, 44480, 44481, 44484,
            44488, 44496, 44497, 44499, 44508, 44512, 44516, 44536, 44537, 44540, 44543, 44544, 44545, 44552, 44553, 44555,
            44557, 44564, 44592, 44593, 44596, 44599, 44600, 44602, 44608, 44609, 44611, 44613, 44614, 44618, 44620, 44621,
            44622, 44624, 44628, 44630, 44636, 44637, 44639, 44640, 44641, 44645, 44648, 44649, 44652, 44656, 44664, 44665,
            44667, 44668, 44669, 44676, 44677, 44684, 44732, 44733, 44734, 44736, 44740, 44748, 44749, 44751, 44752, 44753,
            44760, 44761, 44764, 44776, 44779, 44781, 44788, 44792, 44796, 44807, 44808, 44813, 44816, 44844, 44845, 44848,
            44850, 44852, 44860, 44861, 44863, 44865, 44866, 44867, 44872, 44873, 44880, 44892, 44893, 44900, 44901, 44921,
            44928, 44932, 44936, 44944, 44945, 44949, 44956, 44984, 44985, 44988, 44992, 44999, 45000, 45001, 45003, 45005,
            45006, 45012, 45020, 45032, 45033, 45040, 45041, 45044, 45048, 45056, 45057, 45060, 45068, 45072, 45076, 45084,
            45085, 45096, 45124, 45125, 45128, 45130, 45132, 45134, 45139, 45140, 45141, 45143, 45145, 45149, 45180, 45181,
            45184, 45188, 45196, 45197, 45199, 45201, 45208, 45209, 45210, 45212, 45215, 45216, 45217, 45218, 45224, 45225,
            45227, 45228, 45229, 45230, 45231, 45233, 45235, 45236, 45237, 45240, 45244, 45252, 45253, 45255, 45256, 45257,
            45264, 45265, 45268, 45272, 45280, 45285, 45320, 45321, 45323, 45324, 45328, 45330, 45331, 45336, 45337, 45339,
            45340, 45341, 45347, 45348, 45349, 45352, 45356, 45364, 45365, 45367, 45368, 45369, 45376, 45377, 45380, 45384,
            45392, 45393, 45396, 45397, 45400, 45404, 45408, 45432, 45433, 45436, 45440, 45442, 45448, 45449, 45451, 45453,
            45458, 45459, 45460, 45464, 45468, 45480, 45516, 45520, 45524, 45532, 45533, 45535, 45544, 45545, 45548, 45552,
            45561, 45563, 45565, 45572, 45573, 45576, 45579, 45580, 45588, 45589, 45591, 45593, 45600, 45620, 45628, 45656,
            45660, 45664, 45672, 45673, 45684, 45685, 45692, 45700, 45701, 45705, 45712, 45713, 45716, 45720, 45721, 45722,
            45728, 45729, 45731, 45733, 45734, 45738, 45740, 45744, 45748, 45768, 45769, 45772, 45776, 45778, 45784, 45785,
            45787, 45789, 45794, 45796, 45797, 45798, 45800, 45803, 45804, 45805, 45806, 45807, 45811, 45812, 45813, 45815,
            45816, 45817, 45818, 45819, 45823, 45824, 45825, 45828, 45832, 45840, 45841, 45843, 45844, 45845, 45852, 45908,
            45909, 45910, 45912, 45915, 45916, 45918, 45919, 45924, 45925, 45927, 45929, 45931, 45934, 45936, 45937, 45940,
            45944, 45952, 45953, 45955, 45956, 45957, 45964, 45968, 45972, 45984, 45985, 45992, 45996, 46020, 46021, 46024,
            46027, 46028, 46030, 46032, 46036, 46037, 46039, 46041, 46043, 46045, 46048, 46052, 46056, 46076, 46096, 46104,
            46108, 46112, 46120, 46121, 46123, 46132, 46160, 46161, 46164, 46168, 46176, 46177, 46179, 46181, 46188, 46208,
            46216, 46237, 46244, 46248, 46252, 46261, 46263, 46265, 46272, 46276, 46280, 46288, 46293, 46300, 46301, 46304,
            46307, 46308, 46310, 46316, 46317, 46319, 46321, 46328, 46356, 46357, 46360, 46363, 46364, 46372, 46373, 46375,
            46376, 46377, 46378, 46384, 46385, 46388, 46392, 46400, 46401, 46403, 46404, 46405, 46411, 46412, 46413, 46416,
            46420, 46428, 46429, 46431, 46432, 46433, 46496, 46497, 46500, 46504, 46506, 46507, 46512, 46513, 46515, 46516,
            46517, 46523, 46524, 46525, 46528, 46532, 46540, 46541, 46543, 46544, 46545, 46552, 46572, 46608, 46609, 46612,
            46616, 46629, 46636, 46644, 46664, 46692, 46696, 46748, 46749, 46752, 46756, 46763, 46764, 46769, 46804, 46832,
            46836, 46840, 46848, 46849, 46853, 46888, 46889, 46892, 46895, 46896, 46904, 46905, 46907, 46916, 46920, 46924,
            46932, 46933, 46944, 46948, 46952, 46960, 46961, 46963, 46965, 46972, 46973, 46976, 46980, 46988, 46989, 46991,
            46992, 46993, 46994, 46998, 46999, 47000, 47001, 47004, 47008, 47016, 47017, 47019, 47020, 47021, 47028, 47029,
            47032, 47047, 47049, 47084, 47085, 47088, 47092, 47100, 47101, 47103, 47104, 47105, 47111, 47112, 47113, 47116,
            47120, 47128, 47129, 47131, 47133, 47140, 47141, 47144, 47148, 47156, 47157, 47159, 47160, 47161, 47168, 47172,
            47185, 47187, 47196, 47197, 47200, 47204, 47212, 47213, 47215, 47217, 47224, 47228, 47245, 47272, 47280, 47284,
            47288, 47296, 47297, 47299, 47301, 47308, 47312, 47316, 47325, 47327, 47329, 47336, 47337, 47340, 47344, 47352,
            47353, 47355, 47357, 47364, 47384, 47392, 47420, 47421, 47424, 47428, 47436, 47439, 47441, 47448, 47449, 47452,
            47456, 47464, 47465, 47467, 47469, 47476, 47477, 47480, 47484, 47492, 47493, 47495, 47497, 47498, 47501, 47502,
            47532, 47533, 47536, 47540, 47548, 47549, 47551, 47553, 47560, 47561, 47564, 47566, 47567, 47568, 47569, 47570,
            47576, 47577, 47579, 47581, 47582, 47585, 47587, 47588, 47589, 47592, 47596, 47604, 47605, 47607, 47608, 47609,
            47610, 47616, 47617, 47624, 47637, 47672, 47673, 47676, 47680, 47682, 47688, 47689, 47691, 47693, 47694, 47699,
            47700, 47701, 47704, 47708, 47716, 47717, 47719, 47720, 47721, 47728, 47729, 47732, 47736, 47747, 47748, 47749,
            47751, 47756, 47784, 47785, 47787, 47788, 47792, 47794, 47800, 47801, 47803, 47805, 47812, 47816, 47832, 47833,
            47868, 47872, 47876, 47885, 47887, 47889, 47896, 47900, 47904, 47913, 47915, 47924, 47925, 47926, 47928, 47931,
            47932, 47933, 47934, 47940, 47941, 47943, 47945, 47949, 47951, 47952, 47956, 47960, 47969, 47971, 47980, 48008,
            48012, 48016, 48036, 48040, 48044, 48052, 48055, 48064, 48068, 48072, 48080, 48083, 48120, 48121, 48124, 48127,
            48128, 48130, 48136, 48137, 48139, 48140, 48141, 48143, 48145, 48148, 48149, 48150, 48151, 48152, 48155, 48156,
            48157, 48158, 48159, 48164, 48165, 48167, 48169, 48173, 48176, 48177, 48180, 48184, 48192, 48193, 48195, 48196,
            48197, 48201, 48204, 48205, 48208, 48221, 48260, 48261, 48264, 48267, 48268, 48270, 48276, 48277, 48279, 48281,
            48282, 48288, 48289, 48292, 48295, 48296, 48304, 48305, 48307, 48308, 48309, 48316, 48317, 48320, 48324, 48333,
            48335, 48336, 48337, 48341, 48344, 48348, 48372, 48373, 48374, 48376, 48380, 48388, 48389, 48391, 48393, 48400,
            48404, 48420, 48428, 48448, 48456, 48457, 48460, 48464, 48472, 48473, 48484, 48488, 48512, 48513, 48516, 48519,
            48520, 48521, 48522, 48528, 48529, 48531, 48533, 48537, 48538, 48540, 48548, 48560, 48568, 48596, 48597, 48600,
            48604, 48617, 48624, 48628, 48632, 48640, 48643, 48645, 48652, 48653, 48656, 48660, 48668, 48669, 48671, 48708,
            48709, 48712, 48716, 48718, 48724, 48725, 48727, 48729, 48730, 48731, 48736, 48737, 48740, 48744, 48746, 48752,
            48753, 48755, 48756, 48757, 48763, 48764, 48765, 48768, 48772, 48780, 48781, 48783, 48784, 48785, 48792, 48793,
            48808, 48848, 48849, 48852, 48855, 48856, 48864, 48867, 48868, 48869, 48876, 48897, 48904, 48905, 48920, 48921,
            48923, 48924, 48925, 48960, 48961, 48964, 48968, 48976, 48977, 48981, 49044, 49072, 49093, 49100, 49101, 49104,
            49108, 49116, 49119, 49121, 49212, 49233, 49240, 49244, 49248, 49256, 49257, 49296, 49297, 49300, 49304, 49312,
            49313, 49315, 49317, 49324, 49325, 49327, 49328, 49331, 49332, 49333, 49334, 49340, 49341, 49343, 49344, 49345,
            49349, 49352, 49353, 49356, 49360, 49368, 49369, 49371, 49372, 49373, 49380, 49381, 49384, 49388, 49396, 49397,
            49399, 49401, 49408, 49412, 49416, 49424, 49429, 49436, 49437, 49438, 49439, 49440, 49443, 49444, 49446, 49447,
            49452, 49453, 49455, 49456, 49457, 49462, 49464, 49465, 49468, 49472, 49480, 49481, 49483, 49484, 49485, 49492,
            49493, 49496, 49500, 49508, 49509, 49511, 49512, 49513, 49520, 49524, 49528, 49541, 49548, 49549, 49550, 49552,
            49556, 49558, 49564, 49565, 49567, 49569, 49573, 49576, 49577, 49580, 49584, 49597, 49604, 49608, 49612, 49620,
            49623, 49624, 49632, 49636, 49640, 49648, 49649, 49651, 49660, 49661, 49664, 49668, 49676, 49677, 49679, 49681,
            49688, 49689, 49692, 49695, 49696, 49704, 49705, 49707, 49709, 49711, 49713, 49714, 49716, 49736, 49744, 49745,
            49748, 49752, 49760, 49765, 49772, 49773, 49776, 49780, 49788, 49789, 49791, 49793, 49800, 49801, 49808, 49816,
            49819, 49821, 49828, 49829, 49832, 49836, 49837, 49844, 49845, 49847, 49849, 49884, 49885, 49888, 49891, 49892,
            49899, 49900, 49901, 49903, 49905, 49910, 49912, 49913, 49915, 49916, 49920, 49928, 49929, 49932, 49933, 49939,
            49940, 49941, 49944, 49948, 49956, 49957, 49960, 49961, 49989, 50024, 50025, 50028, 50032, 50034, 50040, 50041,
            50044, 50045, 50052, 50056, 50060, 50112, 50136, 50137, 50140, 50143, 50144, 50146, 50152, 50153, 50157, 50164,
            50165, 50168, 50184, 50192, 50212, 50220, 50224, 50228, 50236, 50237, 50248, 50276, 50277, 50280, 50284, 50292,
            50293, 50297, 50304, 50324, 50332, 50360, 50364, 50409, 50416, 50417, 50420, 50424, 50426, 50431, 50432, 50433,
            50444, 50448, 50452, 50460, 50472, 50473, 50476, 50480, 50488, 50489, 50491, 50493, 50500, 50501, 50504, 50505,
            50506, 50508, 50509, 50510, 50515, 50516, 50517, 50519, 50520, 50521, 50525, 50526, 50528, 50529, 50532, 50536,
            50544, 50545, 50547, 50548, 50549, 50556, 50557, 50560, 50564, 50567, 50572, 50573, 50575, 50577, 50581, 50583,
            50584, 50588, 50592, 50601, 50612, 50613, 50616, 50617, 50619, 50620, 50621, 50622, 50628, 50629, 50630, 50631,
            50632, 50633, 50634, 50636, 50638, 50640, 50641, 50644, 50648, 50656, 50657, 50659, 50661, 50668, 50669, 50670,
            50672, 50676, 50678, 50679, 50684, 50685, 50686, 50687, 50688, 50689, 50693, 50694, 50695, 50696, 50700, 50704,
            50712, 50713, 50715, 50716, 50724, 50725, 50728, 50732, 50733, 50734, 50736, 50739, 50740, 50741, 50743, 50745,
            50747, 50752, 50753, 50756, 50760, 50768, 50769, 50771, 50772, 50773, 50780, 50781, 50784, 50796, 50799, 50801,
            50808, 50809, 50812, 50816, 50824, 50825, 50827, 50829, 50836, 50837, 50840, 50844, 50852, 50853, 50855, 50857,
            50864, 50865, 50868, 50872, 50873, 50874, 50880, 50881, 50883, 50885, 50892, 50893, 50896, 50900, 50908, 50909,
            50912, 50913, 50920, 50921, 50924, 50928, 50936, 50937, 50941, 50948, 50949, 50952, 50956, 50964, 50965, 50967,
            50969, 50976, 50977, 50980, 50984, 50992, 50993, 50995, 50997, 50999, 51004, 51005, 51008, 51012, 51018, 51020,
            51021, 51023, 51025, 51026, 51027, 51028, 51029, 51030, 51031, 51032, 51036, 51040, 51048, 51051, 51060, 51061,
            51064, 51068, 51069, 51070, 51075, 51076, 51077, 51079, 51080, 51081, 51082, 51086, 51088, 51089, 51092, 51094,
            51095, 51096, 51098, 51104, 51105, 51107, 51108, 51109, 51110, 51116, 51117, 51120, 51124, 51132, 51133, 51135,
            51136, 51137, 51144, 51145, 51148, 51150, 51152, 51160, 51165, 51172, 51176, 51180, 51200, 51201, 51204, 51208,
            51210, 51216, 51217, 51219, 51221, 51222, 51228, 51229, 51232, 51236, 51244, 51245, 51247, 51249, 51256, 51260,
            51264, 51272, 51273, 51276, 51277, 51284, 51312, 51313, 51316, 51320, 51322, 51328, 51329, 51331, 51333, 51334,
            51335, 51339, 51340, 51341, 51348, 51357, 51359, 51361, 51368, 51388, 51389, 51396, 51400, 51404, 51412, 51413,
            51415, 51417, 51424, 51425, 51428, 51445, 51452, 51453, 51456, 51460, 51461, 51462, 51468, 51469, 51471, 51473,
            51480, 51500, 51508, 51536, 51537, 51540, 51544, 51552, 51553, 51555, 51564, 51568, 51572, 51580, 51592, 51593,
            51596, 51600, 51608, 51609, 51611, 51613, 51648, 51649, 51652, 51655, 51656, 51658, 51664, 51665, 51667, 51669,
            51670, 51673, 51674, 51676, 51677, 51680, 51682, 51684, 51687, 51692, 51693, 51695, 51696, 51697, 51704, 51705,
            51708, 51712, 51720, 51721, 51723, 51724, 51725, 51732, 51736, 51753, 51788, 51789, 51792, 51796, 51804, 51805,
            51807, 51808, 51809, 51816, 51837, 51844, 51864, 51900, 51901, 51904, 51908, 51916, 51917, 51919, 51921, 51923,
            51928, 51929, 51936, 51948, 51956, 51976, 51984, 51988, 51992, 52000, 52001, 52033, 52040, 52041, 52044, 52048,
            52056, 52057, 52061, 52068, 52088, 52089, 52124, 52152, 52180, 52196, 52199, 52201, 52236, 52237, 52240, 52244,
            52252, 52253, 52257, 52258, 52263, 52264, 52265, 52268, 52270, 52272, 52280, 52281, 52283, 52284, 52285, 52286,
            52292, 52293, 52296, 52300, 52308, 52309, 52311, 52312, 52313, 52320, 52324, 52326, 52328, 52336, 52341, 52376,
            52377, 52380, 52384, 52392, 52393, 52395, 52396, 52397, 52404, 52405, 52408, 52412, 52420, 52421, 52423, 52425,
            52432, 52436, 52452, 52460, 52464, 52481, 52488, 52489, 52492, 52496, 52504, 52505, 52507, 52509, 52516, 52520,
            52524, 52537, 52572, 52576, 52580, 52588, 52589, 52591, 52593, 52600, 52616, 52628, 52629, 52632, 52636, 52644,
            52645, 52647, 52649, 52656, 52676, 52684, 52688, 52712, 52716, 52720, 52728, 52729, 52731, 52733, 52740, 52744,
            52748, 52756, 52761, 52768, 52769, 52772, 52776, 52784, 52785, 52787, 52789, 52824, 52825, 52828, 52831, 52832,
            52833, 52840, 52841, 52843, 52845, 52852, 52853, 52856, 52860, 52868, 52869, 52871, 52873, 52880, 52881, 52884,
            52888, 52896, 52897, 52899, 52900, 52901, 52908, 52909, 52929, 52964, 52965, 52968, 52971, 52972, 52980, 52981,
            52983, 52984, 52985, 52992, 52993, 52996, 53000, 53008, 53009, 53011, 53013, 53020, 53024, 53028, 53036, 53037,
            53039, 53040, 53041, 53048, 53076, 53077, 53080, 53084, 53092, 53093, 53095, 53097, 53104, 53105, 53108, 53112,
            53120, 53125, 53132, 53153, 53160, 53168, 53188, 53216, 53217, 53220, 53224, 53232, 53233, 53235, 53237, 53244,
            53248, 53252, 53265, 53272, 53293, 53300, 53301, 53304, 53308, 53316, 53317, 53319, 53321, 53328, 53332, 53336,
            53344, 53356, 53357, 53360, 53364, 53372, 53373, 53377, 53412, 53413, 53416, 53420, 53428, 53429, 53431, 53433,
            53440, 53441, 53444, 53448, 53449, 53456, 53457, 53459, 53460, 53461, 53468, 53469, 53472, 53476, 53484, 53485,
            53487, 53488, 53489, 53496, 53517, 53552, 53553, 53556, 53560, 53562, 53568, 53569, 53571, 53572, 53573, 53580,
            53581, 53584, 53588, 53596, 53597, 53599, 53601, 53608, 53612, 53628, 53636, 53640, 53664, 53665, 53668, 53672,
            53680, 53681, 53683, 53685, 53690, 53692, 53696, 53720, 53748, 53752, 53767, 53769, 53776, 53804, 53805, 53808,
            53812, 53820, 53821, 53823, 53825, 53832, 53852, 53860, 53888, 53889, 53892, 53896, 53904, 53905, 53909, 53916,
            53920, 53924, 53932, 53937, 53944, 53945, 53948, 53951, 53952, 53954, 53960, 53961, 53963, 53972, 53976, 53980,
            53988, 53989, 54000, 54001, 54004, 54008, 54016, 54017, 54019, 54021, 54028, 54029, 54030, 54032, 54036, 54038,
            54044, 54045, 54047, 54048, 54049, 54053, 54056, 54057, 54060, 54064, 54072, 54073, 54075, 54076, 54077, 54084,
            54085, 54140, 54141, 54144, 54148, 54156, 54157, 54159, 54160, 54161, 54168, 54169, 54172, 54176, 54184, 54185,
            54187, 54189, 54196, 54200, 54204, 54212, 54213, 54216, 54217, 54224, 54232, 54241, 54243, 54252, 54253, 54256,
            54260, 54268, 54269, 54271, 54273, 54280, 54301, 54336, 54340, 54364, 54368, 54372, 54381, 54383, 54392, 54393,
            54396, 54399, 54400, 54402, 54408, 54409, 54411, 54413, 54420, 54441, 54476, 54480, 54484, 54492, 54495, 54504,
            54508, 54512, 54520, 54523, 54525, 54532, 54536, 54540, 54548, 54549, 54551, 54588, 54589, 54592, 54596, 54604,
            54605, 54607, 54609, 54616, 54617, 54620, 54624, 54629, 54632, 54633, 54635, 54637, 54644, 54645, 54648, 54652,
            54660, 54661, 54663, 54664, 54665, 54672, 54693, 54728, 54729, 54732, 54736, 54738, 54744, 54745, 54747, 54749,
            54756, 54757, 54760, 54764, 54772, 54773, 54775, 54777, 54784, 54785, 54788, 54792, 54800, 54801, 54803, 54804,
            54805, 54812, 54816, 54820, 54829, 54840, 54841, 54844, 54848, 54853, 54856, 54857, 54859, 54861, 54865, 54868,
            54869, 54872, 54876, 54887, 54889, 54896, 54897, 54900, 54915, 54917, 54924, 54925, 54928, 54932, 54941, 54943,
            54945, 54952, 54956, 54960, 54969, 54971, 54980, 54981, 54984, 54988, 54993, 54996, 54999, 55001, 55008, 55012,
            55016, 55024, 55029, 55036, 55037, 55040, 55044, 55057, 55064, 55065, 55068, 55072, 55080, 55081, 55083, 55085,
            55092, 55093, 55096, 55100, 55108, 55111, 55113, 55120, 55121, 55124, 55126, 55127, 55128, 55129, 55136, 55137,
            55139, 55141, 55145, 55148, 55152, 55156, 55164, 55165, 55169, 55176, 55177, 55180, 55184, 55192, 55193, 55195,
            55197, 04352, 04353, 04354, 04355, 04356, 04357, 04358, 04359, 04360, 04361, 04362, 04363, 04364, 04365, 04366,
            04367, 04368, 04369, 04370, 04449, 04450, 04451, 04452, 04453, 04454, 04455, 04456, 04457, 04461, 04462, 04466,
            04467, 04469, 47252, 49968, 50108, 50388, 52012, 65535,
        };

        private static readonly Dictionary<ushort, int> G4ValueId = G4Values
            .Select((value, index) => new KeyValuePair<ushort, int>(value, index))
            .ToDictionary(pair => pair.Key, pair => pair.Value);

        private static readonly Dictionary<ushort, int> G4CharId = G4Chars
            .Select((value, index) => new KeyValuePair<ushort, int>(value, index))
            .GroupBy(z => z.Key).Select(z => z.First()) // 65370 & 9327-9341 are in there twice?
            .ToDictionary(pair => pair.Key, pair => pair.Value);

        #endregion
    }
}
